package cn.zyjblogs.config.security;

import cn.zyjblogs.server.user.po.OauthUserDetails;
import cn.zyjblogs.starter.common.entity.response.HttpCode;
import cn.zyjblogs.starter.common.exception.AuthRuntimeException;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.Collection;

/**
 * @author zhuyijun
 */
@Log4j2
@Component("oauthAuthenticationProvider")
public class OauthAuthenticationProvider extends DaoAuthenticationProvider {
    private UserDetailsService userDetailsService;
    private PasswordEncoder passwordEncoder;

    public OauthAuthenticationProvider(UserDetailsService userDetailsService,
                                       PasswordEncoder passwordEncoder
    ) {
        this.passwordEncoder = passwordEncoder;
        this.userDetailsService = userDetailsService;
        this.setPasswordEncoder(passwordEncoder);
        setUserDetailsService(userDetailsService);
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        if (authentication.getCredentials() == null) {
            this.logger.debug("密码为空");
            throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        }
        String password = (String) authentication.getCredentials();
        //获取用户信息
        UserDetails user = userDetailsService.loadUserByUsername(username);
        if (user == null) {
            this.logger.debug("用户不存在");
            throw new AuthRuntimeException(HttpCode.UNAUTHORIZED, "用户不存在");
        }
        OauthUserDetails userDetails = (OauthUserDetails) user;
        //比较前端传入的密码明文和数据库中加密的密码是否相等
        if (!passwordEncoder.matches(password, userDetails.getPassword())) {
            this.logger.debug("密码不正确");
            throw new AuthRuntimeException(HttpCode.BAD_REQUEST, "密码不正确");
        }
        //获取用户权限信息
        Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
        authorities.forEach(x -> log.info("{}", x));
        return new UsernamePasswordAuthenticationToken(userDetails, password, authorities);
    }

    /**
     * 认证
     *
     * @param userDetails
     * @param authentication
     * @throws AuthenticationException
     */
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        super.additionalAuthenticationChecks(userDetails, authentication);
    }
}
